package com.sophialex.health.record.common.bind.swt.annotations;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.regex.Pattern;

import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.ui.part.ViewPart;

import com.sophia.pojo.AbstractModelObject;
import com.sophialex.health.record.common.bind.swt.annotations.helper.ComboBindHelper;

public class ComboDataBindToProcessor extends AbstractBindingProcessor {

	protected ComboBindHelper helper;

	public ComboDataBindToProcessor(ViewPart view, Field f,
			AnnotionProcessor parent) {
		super(view, f, parent);
		helper = ComboBindHelper.getInstance(f);
	}

	protected void bind() {

		parent.out("--->" + helper.getBeanPath() + "["
				+ lastElementType.getSimpleName() + "]:\r\n");
		parent.out("   Annotation:"
				+ helper.toString().substring(
						helper.toString().indexOf(".ComboDataBindTo") + 1)
				+ "\r\n");

		if (!lastElementType.equals(Integer.class)
				&& !lastElementType.equals(String.class)
				&& !lastElementType.equals(int.class)
				&& !lastElementType.equals(Long.class)
				&& !lastElementType.equals(long.class)) {
			parent
					.out("beanPath、dataPath的最后一级属性只能为String、int/Integer、long/Long.");
			// System.exit(-1);
		}

		String value = computeBeanPropValue(view, helper.getBeanPath().split(
				"\\."))
				+ "";
		// parent.out(value + "\r\n");

		final Combo combo = (Combo) getFieldValue(view, f.getName());
		select(combo, value);
		int itemCnt = combo.getItemCount();
		for (int i = 0; i < itemCnt; i++) {
			String s = combo.getItem(i);
			Object data = getData(combo, s);
			if (value.equals(computeBeanPropValue(data, helper.getDataPath()
					.split("\\."))
					+ "")) {
				combo.select(i);
				break;
			}
		}

		final String[] beanPath = helper.getBeanPath().split("\\.");
		String[] tmpPath = new String[beanPath.length - 1];
		System.arraycopy(beanPath, 0, tmpPath, 0, tmpPath.length);
		final Object o = computeBeanPropValue(view, tmpPath);

		// 触发一次变更
		if (combo.getSelectionIndex() > -1) {
			String s = combo.getItem(combo.getSelectionIndex());
			Object data = getData(combo, s);
			String v = computeBeanPropValue(data, helper.getDataPath().split(
					"\\."))
					+ "";
			setFieldValue(o, beanPath[beanPath.length - 1], v);
		}

		combo.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				String s = combo.getItem(combo.getSelectionIndex());
				Object data = getData(combo, s);
				String[] dataPath = helper.getDataPath().split("\\.");
				String value = computeBeanPropValue(data, dataPath) + "";

				setFieldValue(o, beanPath[beanPath.length - 1], value);
			}
		});

		AbstractModelObject mo = (AbstractModelObject) o;
		mo.addPropertyChangeListener(beanPath[beanPath.length - 1],
				new PropertyChangeListener() {

					public void propertyChange(PropertyChangeEvent evt) {
						String value = evt.getNewValue() + "";
						select(combo, value);

					}
				});
		parent
				.out("    binding by Combo'SelectionListener and PropertyChangeListener.\r\n");
	}

	private void select(Combo combo, String value) {
		int itemCnt = combo.getItemCount();
		if (itemCnt < 1)
			return;
		int i = 0;
		for (; i < itemCnt; i++) {
			String s = combo.getItem(i);
			Object data = getData(combo, s);
			if (value.equals(computeBeanPropValue(data, helper.getDataPath()
					.split("\\."))
					+ "")) {
				combo.select(i);
				break;
			}
		}
		if (i >= itemCnt)
			combo.select(0);
	}

	protected Object computeBeanPropValue(Object bean, String[] beanPath) {
		if (beanPath.length == 1) {
			Object value = null;

			value = getFieldValue(bean, beanPath[0]);

			return value;
		} else {
			Object o = getFieldValue(bean, beanPath[0]);
			String[] newPath = new String[beanPath.length - 1];
			System.arraycopy(beanPath, 1, newPath, 0, beanPath.length - 1);
			return computeBeanPropValue(o, newPath);
		}
	}

	private Object getData(Combo combo, String key) {
		Method getData = null;
		Object data = null;
		try {
			getData = combo.getClass().getMethod("getData", String.class);
			data = getData.invoke(combo, key);
			if (data == null)
				throw new RuntimeException(f.getName() + "未正常初始化。");
		} catch (Exception e1) {
			e1.printStackTrace();
			// System.exit(-1);
		}
		return data;
	}

	protected void vadidateAnnotation() {
		
		if (helper.getDataPath() == null
				|| helper.getDataPath().trim().length() < 1)
			throw new BadBindingException(helper.toString() + "的属性dataPath不能为空");
		if (helper.getBeanPath() == null
				|| helper.getBeanPath().trim().length() < 1)
			throw new BadBindingException(helper.toString() + "的属性beanPath不能为空");
		if (helper.getBeanPath().split("\\.").length < 2)
			throw new BadBindingException("ComoboData.beanPath不能少于两段");
	}

	// 校验是否Combo
	protected void validateSwtWiget(Field f) {

		if (!f.getType().equals(Combo.class)) {
			throw new BadBindingException("字段"
					+ view.getClass().getSimpleName() + "." + f.getName() + "["
					+ f.getType().getName() + "]不是有效的Combo部件");
		}

	}

	@Override
	protected String getBeanPath() {

		return helper.getBeanPath();
	}

	protected void setFieldValue(Object o, String fieldName, String value) {
		Field f = null;
		List<Field> fs = getFields(o.getClass(), true);
		for (Field f1 : fs) {
			if (f1.getName().equals(fieldName))
				f = f1;
		}
		if (f != null) {
			f.setAccessible(true);
			try {
				if (lastElementType.equals(String.class)) {
					f.set(o, value);
				} else if (lastElementType.equals(Integer.class)) {// Integer
					f.set(o, Integer.valueOf(value));
				} else if (lastElementType.equals(int.class)) {// int
					f.set(o, Long.parseLong(value));
				} else if (lastElementType.equals(Long.class)) {// Long
					f.set(o, Long.valueOf(value));
				} else if (lastElementType.equals(long.class)) {// long
					f.set(o, Long.parseLong(value));
				} else {
					throw new RuntimeException(
							"["
									+ f.getName()
									+ "]要用ComboDataBindTo的字段只能是String、int/Integer、Long/long");
				}
			} catch (Exception e) {
				e.printStackTrace();
				// System.exit(-1);
			}
			return;
		}
		// try {
		// f = o.getClass().getDeclaredField(fieldName);
		// f.setAccessible(true);
		// try {
		// if (lastElementType.equals(String.class)) {
		// f.set(o, value);
		// } else if (lastElementType.equals(Integer.class)) {// Integer
		// f.set(o, Integer.valueOf(value));
		// } else {// int
		// f.set(o, Integer.parseInt(value));
		// }
		// } catch (Exception e) {
		// e.printStackTrace();
		// System.exit(-1);
		// }
		//
		// } catch (Exception e) {
		// e.printStackTrace();
		// 若没有名为fieldName的字段，那尝试调用getter
		String name = "set" + Character.toUpperCase(fieldName.charAt(0))
				+ fieldName.substring(1);
		//parent.out(name + "\r\n");
		Method setter = null;
		try {
			if (lastElementType.equals(String.class)) {
				setter = o.getClass().getMethod(name, String.class);
			} else if (lastElementType.equals(Integer.class)) {
				setter = o.getClass().getMethod(name, Integer.class);
			} else if (lastElementType.equals(int.class)) {
				setter = o.getClass().getMethod(name, int.class);
			} else if (lastElementType.equals(long.class)) {
				setter = o.getClass().getMethod(name, long.class);
			} else {
				setter = o.getClass().getMethod(name, Long.class);
			}
		} catch (Exception e1) {
			e1.printStackTrace();
			// System.exit(-1);// 没办法了，退出
		}
		try {
			if (lastElementType.equals(String.class)) {
				setter.invoke(o, value);
			} else if (lastElementType.equals(int.class)
					|| lastElementType.equals(Integer.class)) {// int
				setter.invoke(o, Integer.parseInt(value));
			} else {// long
				setter.invoke(o, Long.parseLong(value));
			}
		} catch (Exception e1) {
			e1.printStackTrace();
			// System.exit(-1);
		}

		// }

	}

}